package com.lingyue.commons.jwt;

import com.lingyue.commons.constants.UserRoleConst;
import com.lingyue.commons.enums.LevelEnum;
import com.lingyue.commons.enums.ResultCodeEnum;
import com.lingyue.commons.exceptions.CommRuntimeException;
import com.lingyue.commons.jwt.domain.UserInfo;
import com.lingyue.commons.request.RequestHolderHelper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author cl
 * @version 1.0 on 2019-11-08 16:45:00.
 */
@Slf4j
public class JwtHelper {

    /**
     * jwt 加密解密密钥
     */
    private static final String JWT_SECRET = "sXwn0kKN3/tTeQAjCZZb6g==";

    /**
     * jwt id
     */
    private static final String JWT_ID = "tokenId";

    /**
     * jwt签名密钥
     */
    private static SecretKey secretKey = null;

    /**
     * header Authorization
     */
    private static final String AUTHORIZATION = "Authorization";

    /**
     * 授权认证方式
     */
    private static final String AUTHORIZATION_PREFIX = "Bearer ";

    /**
     * 默认过期时间
     */
    private final static long TOKEN_EXP = 2 * 60 * 60 * 1000;

    /**
     * 生成默认2小时有效token
     *
     * @param claims
     * @return
     */
    public static String generate(Map<String, Object> claims) {
        return generate(claims, TOKEN_EXP);
    }

    /**
     * 生成指定时长有效token 单位ms
     *
     * @param claims
     * @param millisecond
     * @return
     */
    public static String generate(Map<String, Object> claims, long millisecond) {
        initSecretKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        Date expired = new Date(nowMillis + millisecond);
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        return Jwts.builder()
                .setClaims(claims)
                .setId(JWT_ID)
                .setIssuedAt(now)
                .setExpiration(expired)
                .signWith(signatureAlgorithm, secretKey)
                .compact();
    }

    /**
     * token校验
     *
     * @param jwt
     * @return
     */
    public static Claims verify(String jwt) {
        try {
            initSecretKey();
            Claims claims = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt).getBody();
            return claims;
        } catch (SignatureException e) {
            log.error("jwt解析失败！错误信息---->{}", e);
            throw new CommRuntimeException(ResultCodeEnum.TOKEN_DECRYPT);
        }
    }

    public static void initSecretKey() {
        if (null == secretKey) {
            byte[] encodedKey = Base64.getDecoder().decode(JWT_SECRET);
            secretKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        }
    }

    public static UserInfo getUserInfo() {
        try {
            HttpServletRequest request = RequestHolderHelper.getRequest();
            String authorization = request.getHeader(AUTHORIZATION);
            if (StringUtils.isEmpty(authorization)) throw new CommRuntimeException(ResultCodeEnum.TOKEN_INVALID);
            String jwtToken = authorization.replaceFirst(AUTHORIZATION_PREFIX, "");
            if (StringUtils.isEmpty(jwtToken)) throw new CommRuntimeException(ResultCodeEnum.TOKEN_INVALID);
            initSecretKey();
            Claims claims = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwtToken).getBody();
            UserInfo userInfo = getUserInfo(claims);
            if(!UserRoleConst.get().containsAll(userInfo.getRoles())) {
                throw new CommRuntimeException(ResultCodeEnum.LEVEL_INVALID);
            }
            return userInfo;
        } catch (SignatureException e) {
            log.error("jwt解析失败！错误信息---->{}", e);
            throw new CommRuntimeException(ResultCodeEnum.TOKEN_DECRYPT);
        }
    }


    public static UserInfo getUserInfo(Claims claims) {

        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(claims.get("userId", Integer.class));
        userInfo.setAccount(claims.get("account", String.class));
        userInfo.setAccountName(claims.get("accountName",String.class));
        userInfo.setDmsAccount(claims.get("dmsAccount", String.class));
        userInfo.setDealerId(claims.get("dealerId", String.class));
        userInfo.setLevel(claims.get("organizationId", Integer.class));
        userInfo.setEmail(claims.get("email",String.class));
        userInfo.setRoles(claims.get("roles", ArrayList.class));
        return userInfo;

    }


    public static void main(String[] args) {
        String token = "eyJhbGciOiJIUzI1NiJ9.eyJvcmdhbml6YXRpb25JZCI6MSwidGlja2V0IjoiNzQ2MWVkNmUtYTgzYy00MmM4LWE3YjktM2NkMTcwOWQyNzZjIiwiZG1zQWNjb3VudCI6ImRtc19hZG1pbiIsImRlYWxlcklkIjoiMTExIiwicm9sZXMiOlsiYWRtaW5pc3RyYXRvcuWOuyJdLCJleHAiOjE1NzY2NDU1ODcsInVzZXJJZCI6MSwiaWF0IjoxNTc2MDQwNzg3LCJhY2NvdW50IjoiYWRtaW4iLCJqdGkiOiJ0b2tlbklkIiwidXNlcm5hbWUiOiJhZG1pbiJ9.ZvKELizvYrS0a3RJz639EpY4A897qwKY3pIqFNftcLg";
        Claims claims = verify(token);
        System.out.println();
    }
}
